package scu.maqiang.mesh;

import java.util.HashSet;

import scu.maqiang.numeric.SIMatrix;
import scu.maqiang.numeric.UnorderIntArray;

public class Mesh3T10 extends Mesh {
	
	public Mesh3T10() {
		super();
		nDim = 3;
		nPerElement = 10;
		nPerBoundary = 6;
		nBoundaryPerElement = 4;
		nEdgePerElement = 12;
		nEdgePerBoundary = 6;
		tecplotType = "FETETRAHEDRON";
	}

	public Mesh3T10 cube(int xNum, int yNum, int zNum) {

		int xNodes, yNodes, zNodes;
		int nv, nt, nb;
		int[] L = new int[27];
		int[] B = new int[9];

		xNodes = 2 * xNum + 1;
		yNodes = 2 * yNum + 1;
		zNodes = 2 * zNum + 1;
		nv = xNodes * yNodes * zNodes;
		nt = 6 * xNum * yNum * zNum;
		nb = 4 * (xNum * yNum + yNum * zNum + zNum * xNum);

		nv = nv;
		nt = nt;
		nb = nb;
		initMesh0(nv, nt, nb);
		int count = 0;
		for (int k = 0; k < zNodes; k++) {
			for (int j = 0; j < yNodes; j++) {
				for (int i = 0; i < zNodes; i++) {
					nodes[count++] = new double[]{i / (2.0 * xNum), j / (2.0 * xNum), k / (2.0 * xNum)};
				}
			}
		}

		count = 0;
		for (int k = 0; k < zNum; k++) {
			for (int j = 0; j < yNum; j++) {
				for (int i = 0; i < xNum; i++) {
					L[0] = 2 * (i + xNodes * (j + k * yNodes));
					L[1] = L[0] + 1;
					L[2] = L[1] + 1;
					L[3] = L[0] + xNodes;
					L[4] = L[3] + 1;
					L[5] = L[4] + 1;
					L[6] = L[3] + xNodes;
					L[7] = L[6] + 1;
					L[8] = L[7] + 1;

					for (int ii = 0; ii < 9; ii++) {
						L[9 + ii] = L[ii] + xNodes * yNodes;
						L[18 + ii] = L[9 + ii] + xNodes * yNodes;
					}

					//System.out.println(Arrays.toString(L));
					elements[count++] = new int[]{L[0], L[2], L[8], L[26], L[1], L[5], L[4], L[13], L[14], L[17]};
					elements[count++] = new int[]{L[0], L[20], L[2], L[26], L[10], L[11], L[1], L[13], L[23], L[14]};
					elements[count++] = new int[]{L[0], L[8], L[6], L[26], L[4], L[7], L[3], L[13], L[17], L[16]};
					elements[count++] = new int[]{L[0], L[18], L[20], L[26], L[9], L[19], L[10], L[13], L[22], L[23]};
					elements[count++] = new int[]{L[0], L[6], L[24], L[26], L[3], L[15], L[12], L[13], L[16], L[25]};
					elements[count++] = new int[]{L[0], L[24], L[18], L[26], L[12], L[21], L[9], L[13], L[25], L[22]};
				}
			}
		}

		count = 0;

		for (int j = 0; j < yNum; j++) {
			for (int i = 0; i < xNum; i++) {
				B[0] = 2 * (i + j * xNodes);
				B[1] = B[0] + 1;
				B[2] = B[1] + 1;
				for (int ii = 0; ii < 3; ii++) {
					B[3 + ii] = B[ii] + xNodes;
					B[6 + ii] = B[3 + ii] + xNodes;
				}
//				System.out.println(Arrays.toString(B));
				boundaries[count] = new int[]{B[0], B[8], B[2], B[4], B[5], B[1]};
				boundaryLabel[count++] = 1;
				boundaries[count] = new int[]{B[0], B[6], B[8], B[3], B[7], B[4]};
				boundaryLabel[count++] = 1;
			}
		}

		for (int j = 0; j < yNum; j++) {
			for (int i = 0; i < xNum; i++) {
				int temp = 2 * zNum * xNodes * yNodes;
				B[0] = 2 * (i + j * xNodes) + temp;
				B[1] = B[0] + 1;
				B[2] = B[1] + 1;
				for (int ii = 0; ii < 3; ii++) {
					B[3 + ii] = B[ii] + xNodes;
					B[6 + ii] = B[3 + ii] + xNodes;
				}
				boundaries[count] = new int[]{B[0], B[2], B[8], B[1], B[5], B[4]};
				boundaryLabel[count++] = 2;
				boundaries[count] = new int[]{B[0], B[8], B[6], B[4], B[7], B[3]};
				boundaryLabel[count++] = 2;
			}
		}

		for (int j = 0; j < zNum; j++) {
			for (int i = 0; i < yNum; i++) {
				B[0] = 2 * (i * xNodes + j * xNodes * yNodes);
				B[1] = B[0] + xNodes;
				B[2] = B[1] + xNodes;
				for (int ii = 0; ii < 3; ii++) {
					B[3 + ii] = B[ii] + xNodes * yNodes;
					B[6 + ii] = B[3 + ii] + xNodes * yNodes;
				}
				boundaries[count] = new int[]{B[0], B[8], B[2], B[4], B[5], B[1]};
				boundaryLabel[count++] = 3;
				boundaries[count] = new int[]{B[0], B[6], B[8], B[3], B[7], B[4]};
				boundaryLabel[count++] = 3;
			}
		}

		for (int j = 0; j < zNum; j++) {
			for (int i = 0; i < yNum; i++) {
				B[0] = 2 * xNum + 2 * (i * xNodes + j * xNodes * yNodes);
				B[1] = B[0] + xNodes;
				B[2] = B[1] + xNodes;
				for (int ii = 0; ii < 3; ii++) {
					B[3 + ii] = B[ii] + xNodes * yNodes;
					B[6 + ii] = B[3 + ii] + xNodes * yNodes;
				}
				boundaries[count] = new int[]{B[0], B[2], B[8], B[1], B[5], B[4]};
				boundaryLabel[count++] = 4;
				boundaries[count] = new int[]{B[0], B[8], B[6], B[4], B[7], B[3]};
				boundaryLabel[count++] = 4;
			}
		}

		for (int j = 0; j < zNum; j++) {
			for (int i = 0; i < xNum; i++) {
				B[0] = 2 * (i + j * xNodes * yNodes);
				B[1] = B[0] + 1;
				B[2] = B[1] + 1;
				for (int ii = 0; ii < 3; ii++) {
					B[3 + ii] = B[ii] + xNodes * yNodes;
					B[6 + ii] = B[3 + ii] + xNodes * yNodes;
				}
				boundaries[count] = new int[]{B[0], B[2], B[8], B[1], B[5], B[4]};
				boundaryLabel[count++] = 5;
				boundaries[count] = new int[]{B[0], B[8], B[6], B[4], B[7], B[3]};
				boundaryLabel[count++] = 5;
			}
		}

		for (int j = 0; j < zNum; j++) {
			for (int i = 0; i < xNum; i++) {
				int temp = 2 * yNum * xNodes;
				B[0] = 2 * (i + j * xNodes * yNodes) + temp;
				B[1] = B[0] + 1;
				B[2] = B[1] + 1;
				for (int ii = 0; ii < 3; ii++) {
					B[3 + ii] = B[ii] + xNodes * yNodes;
					B[6 + ii] = B[3 + ii] + xNodes * yNodes;
				}

				boundaries[count] = new int[]{B[0], B[8], B[2], B[4], B[5], B[1]};
				boundaryLabel[count++] = 6;
				boundaries[count] = new int[]{B[0], B[6], B[8], B[3], B[7], B[4]};
				boundaryLabel[count++] = 6;
			}
		}

		return this;
	}

	public Mesh3T10 fromMesh3DT4(Mesh3T4 mesh0) {
		SIMatrix C = mesh0.renumberingEdges();
		C.sort();
		//System.out.println(C);
		int sizeC = C.getNNZ();
		int[] idxI = new int[sizeC];
		int[] idxJ = new int[sizeC];
		int[] value = new int[sizeC];
		int[] number = new int[sizeC];
		C.getTriValues(idxI, idxJ, value);
		for (int i = 0; i < sizeC; i++) {
			number[i] = i;
		}

		nv = sizeC + mesh0.nv;
		nodes = new double[nv][];
		nodeLabel = new int[nv];
		int[][] edges = new int[mesh0.nt][6];
		for (int i = 0; i < mesh0.nt; i++) {
			int[] tet = mesh0.elements[i];
			int d1 = tet[0];
			int d2 = tet[1];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edges[i][0] = j + mesh0.nv;
					break;
				}
			}
			d1 = tet[1];
			d2 = tet[2];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edges[i][1] = j + mesh0.nv;
					break;
				}
			}

			d1 = tet[2];
			d2 = tet[0];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edges[i][2] = j + mesh0.nv;
					break;
				}
			}

			d1 = tet[0];
			d2 = tet[3];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edges[i][3] = j + mesh0.nv;
					break;
				}
			}

			d1 = tet[1];
			d2 = tet[3];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edges[i][4] = j + mesh0.nv;
					break;
				}
			}

			d1 = tet[2];
			d2 = tet[3];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edges[i][5] = j + mesh0.nv;
					break;
				}
			}

		}

		for (int i = 0; i < mesh0.nv; i++) {
			nodes[i] = mesh0.nodes[i].clone();
		}
		for (int i = mesh0.nv; i < nv; i++) {
			nodes[i] = new double[nDim];
		}

		int idx;
		nt = mesh0.nt;
		elements = new int[nt][];
		elementLabel = mesh0.elementLabel.clone();
		for (int i = 0; i < mesh0.nt; i++) {
			int[] tet = mesh0.elements[i];
			double[][] node = new double[4][];
			for (int j = 0; j < 4; j++) {
				node[j] = mesh0.nodes[tet[j]];
			}

			nodes[edges[i][0]] = new double[] { 0.5 * (node[0][0] + node[1][0]), 0.5 * (node[0][1] + node[1][1]), 0.5 * (node[0][2] + node[1][2])};
			nodes[edges[i][1]] = new double[] { 0.5 * (node[1][0] + node[2][0]), 0.5 * (node[1][1] + node[2][1]), 0.5 * (node[1][2] + node[2][2])};
			nodes[edges[i][2]] = new double[] { 0.5 * (node[2][0] + node[0][0]), 0.5 * (node[2][1] + node[0][1]), 0.5 * (node[2][2] + node[0][2])};
			nodes[edges[i][3]] = new double[] { 0.5 * (node[3][0] + node[0][0]), 0.5 * (node[3][1] + node[0][1]), 0.5 * (node[3][2] + node[0][2])};
			nodes[edges[i][4]] = new double[] { 0.5 * (node[3][0] + node[1][0]), 0.5 * (node[3][1] + node[1][1]), 0.5 * (node[3][2] + node[1][2])};
			nodes[edges[i][5]] = new double[] { 0.5 * (node[3][0] + node[2][0]), 0.5 * (node[3][1] + node[2][1]), 0.5 * (node[3][2] + node[2][2])};
			// 单元编号
			int[] tet10Idx = new int[] { tet[0], tet[1], tet[2], tet[3], edges[i][0], edges[i][1], edges[i][2], edges[i][3], edges[i][4], edges[i][5]};
			elements[i] = tet10Idx;
		}

		nb = mesh0.nb;
		int d1, d2;
		int[] midP = new int[3];
		boundaries = new int[nb][];
		boundaryLabel = mesh0.boundaryLabel.clone();
		for (int i = 0; i < nb; i++) {
			int[] li = mesh0.boundaries[i];
			d1 = li[0];
			d2 = li[1];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					midP[0] = j + mesh0.nv;
					break;
				}
			}

			d1 = li[1];
			d2 = li[2];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					midP[1] = j + mesh0.nv;
					break;
				}
			}

			d1 = li[2];
			d2 = li[0];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					midP[2] = j + mesh0.nv;
					break;
				}
			}

			boundaries[i] = new int[] {li[0], li[1], li[2], midP[0], midP[1], midP[2]};
		}
		return this;
	}
	@Override
	public double[] getinteriorPointInElement(double[][] coord) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public double[] getinteriorPointOnBoundary(double[][] coord) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int[][] getBoundarysFromElement(int i) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean checkMesh(double[][] coord) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public int getTecplotNt() {
		// TODO Auto-generated method stub
		return 4 * nt;
	}

	@Override
	public int[][] getEdgesFromElement(int i) {
		int[] ele = elements[i];
		int[][] result = new int[12][];
		result[0] = new int[] {ele[0], ele[4]};
		result[1] = new int[] {ele[4], ele[1]};
		result[2] = new int[] {ele[1], ele[5]};
		result[3] = new int[] {ele[5], ele[2]};
		result[4] = new int[] {ele[2], ele[6]};
		result[5] = new int[] {ele[6], ele[0]};
		result[6] = new int[] {ele[0], ele[7]};
		result[7] = new int[] {ele[7], ele[3]};
		result[8] = new int[] {ele[1], ele[8]};
		result[9] = new int[] {ele[8], ele[3]};
		result[10] = new int[] {ele[2], ele[9]};
		result[11] = new int[] {ele[9], ele[3]};
		return null;
	}

}
